﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tetris
{
    enum FigurePosition
    {
        North,
        East,
        South,
        West
    }

    enum CurrentFigure
    {
        O_Figure,
        T_Figure,
        J_Figure,
        L_Figure,
        Z_Figure,
        S_Figure,
        I_Figure
    }

    class GameLogic
    {
        public GameField field;
        public Drawer drw;
        Figures figure;
        Figures fallingFigure;
        Figures nextFigure;
        CurrentFigure currentFigure;
        List<Node> figureList;
        List<Node> finishedList;
        List<Node> nextfigureList;
        List<Figures> toPrintList;
        //ConsoleKeyInfo key = default(ConsoleKeyInfo);
        private readonly Handler hd;
        Random rnd;
        List<int> coordYCompleteLine;
        int score = 0;
        int currentPoints = 0;
        int completeLines = 0;
        int speed;
        private SoundLayer _player;
        //bool isGameOver = false;
        //bool isPaused = true;
        //bool isNewRound = false;

        public GameLogic(GameField field, Handler keyH, SoundLayer player)
        {
            this.field = field;
            drw = new Drawer();
            drw.FrameDrawer(this.field);
            currentFigure = new CurrentFigure();
            finishedList = new List<Node>();
            figureList = new List<Node>();
            nextfigureList = new List<Node>();
            toPrintList = new List<Figures>();
            speed = 300;
            List<int> coordYCompleteLine = new List<int>();
            rnd = new Random();
            hd = keyH;
            hd.KeyLeft += MoveFigureLeft;
            hd.KeyRight += MoveFigureRight;
            hd.KeyDown += MoveFigureDown;
            hd.KeyUp += RotateFigure;
            _player = player;
        }

        public void FigureListCreation()
        {
            figureList.Add(fallingFigure.nodes[0]);
            figureList.Add(fallingFigure.nodes[1]);
            figureList.Add(fallingFigure.nodes[2]);
            figureList.Add(fallingFigure.nodes[3]);
        }

        public void NextFigureListCreation()
        {
            nextfigureList.Add(nextFigure.nodes[0]);
            nextfigureList.Add(nextFigure.nodes[1]);
            nextfigureList.Add(nextFigure.nodes[2]);
            nextfigureList.Add(nextFigure.nodes[3]);
        }

        public bool IsLeftMoveIsOk()
        {
            bool isLeftSideMoving = true;

            for (int i = 0; i < figureList.Count; i++)
            {
                if (figureList[i].XNode - 1 <= field.StartX - 1)
                {
                    isLeftSideMoving = false;
                }
            }

            for (int i = 0; i < figureList.Count; i++)
            {
                for (int j = 0; j < finishedList.Count; j++)
                {
                    if (figureList[i].XNode - 1 == finishedList[j].XNode && figureList[i].YNode == finishedList[j].YNode)
                    {
                        isLeftSideMoving = false;
                    }
                }
            }
            return isLeftSideMoving;
        }

        public bool IsRightMoveIsOk()
        {
            bool isRightSideMoving = true;

            for (int i = 0; i < figureList.Count; i++)
            {
                if (figureList[i].XNode + 1 >= field.StartX + field.Width)
                {
                    isRightSideMoving = false;
                }
            }

            for (int i = 0; i < figureList.Count; i++)
            {
                for (int j = 0; j < finishedList.Count; j++)
                {
                    if (figureList[i].XNode + 1 == finishedList[j].XNode && figureList[i].YNode == finishedList[j].YNode)
                    {
                        isRightSideMoving = false;
                    }
                }
            }
            return isRightSideMoving;
        }

        public bool IsDownMoveIsOk()
        {
            bool isDownSideMoving = true;

            for (int i = 0; i < figureList.Count; i++)
            {
                if (figureList[i].YNode + 1 >= field.StartY + field.Height)
                {
                    isDownSideMoving = false;
                }
            }

            for(int i = 0; i < figureList.Count; i++)
            {
                for (int j = 0; j < finishedList.Count; j++)
                {
                    if (figureList[i].XNode == finishedList[j].XNode && figureList[i].YNode + 1 == finishedList[j].YNode)
                    {
                        isDownSideMoving = false;
                    }
                }
            }

            return isDownSideMoving;
        }

        public bool isRotateAvailable()
        {
            bool isRotateOK = true;

            if (currentFigure == CurrentFigure.J_Figure || currentFigure == CurrentFigure.L_Figure || currentFigure == CurrentFigure.Z_Figure 
                || currentFigure == CurrentFigure.S_Figure || currentFigure == CurrentFigure.T_Figure)
            {
                if (figureList[2].XNode <= field.StartX || figureList[2].XNode >= field.StartX + field.Width - 1)
                {
                    isRotateOK = false;
                }

            }

            else if (currentFigure == CurrentFigure.I_Figure)
            {
                if (figureList[2].XNode <= field.StartX + 1 || figureList[2].XNode >= field.StartX + field.Width - 1)
                {
                    isRotateOK = false;
                }
            }

            return isRotateOK;
        }
        
        public Figures NextFigureGeneration()
        {

            int a = rnd.Next(1, 8);
            switch (a)
            {
                case 1:
                    {
                        figure = new O_Figure(field);
                        currentFigure = CurrentFigure.O_Figure;
                        break;
                    }
                case 2:
                    {
                        figure = new T_Figure(field);
                        currentFigure = CurrentFigure.T_Figure;
                        break;
                    }
                case 3:
                    {
                        figure = new J_Figure(field);
                        currentFigure = CurrentFigure.J_Figure;
                        break;
                    }
                case 4:
                    {
                        figure = new L_Figure(field);
                        currentFigure = CurrentFigure.L_Figure;
                        break;
                    }
                case 5:
                    {
                        figure = new Z_Figure(field);
                        currentFigure = CurrentFigure.Z_Figure;
                        break;
                    }
                case 6:
                    {
                        figure = new S_Figure(field);
                        currentFigure = CurrentFigure.S_Figure;
                        break;
                    }
                case 7:
                    {
                        figure = new I_Figure(field);
                        currentFigure = CurrentFigure.I_Figure;
                        break;
                    }
                default:
                    break;
            }
            return figure;
        }

        private void MoveFigureLeft(object sender, EventArgs e)
        {
            if (IsLeftMoveIsOk())
            {
                fallingFigure.MoveFigureLeft();
            }
        }

        private void MoveFigureRight(object sender, EventArgs e)
        {
            if (IsRightMoveIsOk())
            {
                fallingFigure.MoveFigureRight();
            }
        }

        private void MoveFigureDown(object sender, EventArgs e)
        {
            if (IsDownMoveIsOk())
            {
                fallingFigure.MoveFigureDown();
            }
        }

        private void RotateFigure(object sender, EventArgs e)
        {
            if (isRotateAvailable())
            {
                fallingFigure.FigureRotate();
            }
        }

        public int IsLineComplete()
        {
            int duplicates = 0;
            int completeLines = 0;
            for (int j = field.Height; j >= 1; j--)
            {
                duplicates = 0;
                for (int i = 0; i < figureList.Count; i++)
                {
                    if (figureList[i].YNode == j)
                    {
                        duplicates++;
                    }
                }
                if (duplicates == field.Width)
                {
                    completeLines++;
                }
            }
            return completeLines;
        }

        public List<int> CoordYCompleteLine()
        {
            int Yduplicate = field.Height;
            int duplicates = 0;
            List<int> duplictesYcoord = new List<int>();
            for (int j = field.Height; j >= 1; j--)
            {
                duplicates = 0;
                for (int i = 0; i < figureList.Count; i++)
                {
                    if (figureList[i].YNode == j)
                    {
                        duplicates++;
                    }
                }
                if (duplicates == field.Width)
                {
                    duplictesYcoord.Add(j);
                }
            }

            return duplictesYcoord;
        }

        public void DeletingCompleteLines(List<int> coordYCompleteLine)
        {
            for (int i = 0; i < finishedList.Count; i++)
            {
                for (int j = 0; j < coordYCompleteLine.Count; j++)
                {
                    if (finishedList[i].YNode == coordYCompleteLine[j])
                    {
                        finishedList.Remove(finishedList[i]);
                        if (i!=0)
                        {
                            --i;
                        }
                        
                    }
                }
            }
        }

        public void CheckForPointAmount(int lines)
        {
            if (lines == 1)
            {
                currentPoints = 100;
            }
            else if (lines == 2)
            {
                currentPoints = 300;
            }
            else if (lines == 3)
            {
                currentPoints = 700;
            }
            else
            {
                currentPoints = 1500;
            }
        }

        public void MoveLogic()
        {
            _player.PlayMusic();
            fallingFigure = NextFigureGeneration();
            FigureListCreation();

            nextFigure = NextFigureGeneration();
            NextFigureListCreation();
            
            foreach (var item in nextfigureList)
            {
                drw.DrawTheNextFigure(field, item);
            }

            do
            {
                hd.Control();
                for (int i = 0; i < figureList.Count; i++)
                {
                    drw.DrawFigure(figureList[i]);
                }
                System.Threading.Thread.Sleep(speed);
                foreach (var item in figureList)
                {
                    drw.ClearFigure(item);
                }


                if (IsDownMoveIsOk())
                {
                    foreach (var item in figureList)
                    {
                        item.MoveDown();
                    }
                }

                for (int i = 0; i < figureList.Count; i++)
                {
                    drw.DrawFigure(figureList[i]);
                }

                System.Threading.Thread.Sleep(speed);

                foreach (var item in figureList)
                {
                    drw.ClearFigure(item);
                }

                //key = default(ConsoleKeyInfo);

                if (!IsDownMoveIsOk())
                {

                    for (int i = 0; i < figureList.Count; i++)
                    {
                        finishedList.Add(figureList[i]);
                    }
                    figureList.Clear();
                    fallingFigure = nextFigure;
                    FigureListCreation();
                    foreach (var item in nextfigureList)
                    {
                        drw.ClearTheNextFigure(field, item);
                    }
                    nextfigureList.Clear();
                    nextFigure = NextFigureGeneration();
                    NextFigureListCreation();
                    foreach (var item in nextfigureList)
                    {
                        drw.DrawTheNextFigure(field, item);
                    }

                    if ((completeLines = IsLineComplete()) > 0)
                    {
                        
                        coordYCompleteLine = CoordYCompleteLine();
                        foreach (var element in finishedList)
                        {
                            drw.ClearFigure(element);
                        }
                        DeletingCompleteLines(coordYCompleteLine);
                        coordYCompleteLine.Sort();
                        for (int j = 0; j < coordYCompleteLine.Count; j++)
                        {
                            foreach (var item in finishedList)
                            {
                                if (item.YNode < coordYCompleteLine[j])
                                {
                                    item.MoveDown();
                                }
                            }
                        }
                        CheckForPointAmount(completeLines);
                        score += currentPoints;
                        drw.DrawTheScore(field, currentPoints, score);
                    }
                }


                foreach (var element in finishedList)
                {
                    drw.DrawFigure(element);
                }
            } while (true);
        }


    }
}
